package com.fingard.net;

import com.fingard.FGBiz;
import com.fingard.diagnostics.LogHelper;
import com.fingard.dsp.bankset.BankFront;
import com.fingard.dsp.bankset.EnBfStatus;
import com.fingard.net.https.HttpsHandler;
import com.fingard.text.StringHelper;
import sun.misc.BASE64Encoder;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSession;
import java.io.*;
import java.net.*;
import java.util.Date;

public class WebRequest {

	private HttpURLConnection httpConnection;
	private URL url;
	private String connCode = "";
	private String connMsg = "";
	public StringBuilder sbLog = null;
	
	public void setSbLog(StringBuilder p_sb){
		sbLog = p_sb;
	}
	
	private static boolean isTrusted = false;
	
	private BankFront preBankFront = null;
	public void setBankFront(BankFront p_bf){
		preBankFront = p_bf;
	}
	
	public void setLogCode(String pLogCode){
		logCode = pLogCode;
	}
	private String logCode;
	private String getLogCode(){
		if(StringHelper.hasAnyChar(logCode)){
			return logCode;
		}else if(preBankFront != null && preBankFront.bankCode!=null){
			logCode = preBankFront.bankCode;
		}else if(url !=null){
			logCode = url.getPath();
		}else{
			logCode = "WebRequest";
		}
		return logCode;
	}
	
	private void setBankFrontException(String p_exMsg){
		if(preBankFront != null){
			preBankFront.frontStatus.status = EnBfStatus.exception;
			preBankFront.frontStatus.statusTime = new Date();
			preBankFront.frontStatus.statusInfo = p_exMsg;
		}
	}
	public WebRequest(String p_addr){
		sbLog = new StringBuilder();
		init(p_addr);
	}
	public WebRequest(String p_addr, BankFront p_bf, StringBuilder p_sb){
		sbLog = p_sb;
		preBankFront = p_bf;
		init(p_addr);
	}
	
	public WebRequest(String p_addr, String pIP, int pPort, String pUser, String pPwd){
		sbLog = new StringBuilder();
		setHttpProxy(pIP, pPort, pUser, pPwd);
		init(p_addr);
	}
	
	private Proxy httpProxy = null;
	private String proxyIp;
	private int proxyPort;
	private String proxyUser;
	private String proxyPwd;
	private boolean isHttpTransmit = false;//dsp之间采用http转发
	public void setHttpTransmit(){
		isHttpTransmit = true;
	}
	
	private void setHttpProxy(String pIP, int pPort, String pUser, String pPwd){

		proxyIp = pIP;
		proxyPort = pPort;
		proxyUser = pUser;
		proxyPwd = pPwd;
		
		if(StringHelper.hasAnyChar(pIP)){
			SocketAddress sa = new InetSocketAddress(proxyIp, proxyPort);
		
			httpProxy = new Proxy(Proxy.Type.HTTP, sa);
		
		}
	}
	
	private String serverAddr = "";
	
	private void init(String p_addr){
		try {
			serverAddr = p_addr;
			if (p_addr.contains("https://")) {
				//url = new URL(null, p_addr, new com.sun.net.ssl.internal.www.protocol.https.Handler());
				if(isTrusted == false){
					HttpsHandler.trustAllHttpsCertificates();
					isTrusted = true;
				}
				HostnameVerifier hv = new HostnameVerifier() {
					public boolean verify(String urlHostName, SSLSession session) {
						return true;
					}
				};
				HttpsURLConnection.setDefaultHostnameVerifier(hv);
				url = new URL(null,p_addr, new sun.net.www.protocol.https.Handler());
			}
			else{
				url = new URL(p_addr);
			}

			boolean enableProxy = FGBiz.dspCenter.dspSet.enableProxy;
			if(httpProxy != null){
				httpConnection = (HttpURLConnection) url.openConnection(httpProxy);
				if(StringHelper.hasAnyChar(proxyUser)){
					String encoded = new String
					      (new BASE64Encoder().encode(new String(this.proxyUser + ":" + this.proxyPwd).getBytes()));
					httpConnection.setRequestProperty("Proxy-Authorization", "Basic " + encoded);
				}
			}
			else if (isHttpTransmit==false && enableProxy) {//非dsp转发，取全局代理配置
				String proxyIP = FGBiz.dspCenter.dspSet.proxyIP;
				int proxyPort = Integer.parseInt(FGBiz.dspCenter.dspSet.proxyPort);

				SocketAddress sa = new InetSocketAddress(proxyIP, proxyPort);
				Proxy proxy = new Proxy(Proxy.Type.HTTP, sa);
				httpConnection = (HttpURLConnection) url.openConnection(proxy);
			} else {
				httpConnection = (HttpURLConnection) url.openConnection();
			}
		} catch (Exception e) {
			FGBiz.limitMsg.exception(getLogCode(),e);
			connCode = ConnState.FAIL;
			connMsg = "连接"+p_addr+"异常："+LogHelper.getStackTraceFirstLine(e);
			String exceptionMsg = LogHelper.getStackTrace(e);
			sbLog.append(exceptionMsg+"\r\n");
			setBankFrontException(exceptionMsg);
		}
	}
	
	
	
	private int connectTimeout = 10000;//10秒
	/**设置连接超时时间，毫秒*/
	public void setConnectTimeout(int p_timeout){
		connectTimeout = p_timeout;
	}
	
	private int readTimeout = 60000;//60秒
	/**设置接受超时时间，毫秒*/
	public void setReadTimeout(int p_timeout){
		readTimeout = p_timeout;
	}
	
	public void setRequestProperty(String p_key, String p_value){
		if(connCode.length()==0){
			httpConnection.setRequestProperty(p_key, p_value);
		}
	}
	
	/**提交字节并取得响应*/
	public String[] upload(byte[] p_upBytes, String p_charsetName){
		String[] retStr = new String[]{"",""};
		retStr[0] = connCode;
		if(connCode.length() == 0){
			if(connectTimeout > 0){
				httpConnection.setConnectTimeout(connectTimeout);
				connectTimeout = 0;
			}
			if(readTimeout > 0){
				httpConnection.setReadTimeout(readTimeout);
				readTimeout = 0;
			}
			OutputStream outputStream = null;
			InputStream inputStream = null;
			try {
				httpConnection.setDoInput(true);// 从服务器获取数据
				
				httpConnection.setUseCaches(false);
				if(p_upBytes != null){
					httpConnection.setDoOutput(true);// 向服务器写入数据
					httpConnection.setRequestMethod("POST");
					httpConnection.setRequestProperty("Content-Length", String.valueOf(p_upBytes.length));
					outputStream = (OutputStream) httpConnection.getOutputStream();
				}
				else{
					httpConnection.setRequestMethod("GET");
				}
			}
			catch (IOException e) {
				FGBiz.limitMsg.exception(getLogCode(),e);
				retStr[0] = ConnState.FAIL;
				retStr[1] = LogHelper.getStackTraceFirstLine(e);
				if(retStr[1].contains("ConnectException")){
					retStr[1] = "连接" + serverAddr + "异常：" + retStr[1];
				}
//				retStr[1] = e.getMessage();//; LogHelper.getStackTrace(e)
				String exMsg = LogHelper.getStackTrace(e);
				sbLog.append(exMsg+"\r\n");
				setBankFrontException(exMsg);
			}
			if(retStr[0].length() == 0){
				try{
					if(p_upBytes != null){
						outputStream.write(p_upBytes);
						outputStream.flush();
						
					}
				    // 获得服务器响应的结果和状态码

			        //int responseCode = httpConnection.getResponseCode();
			        //if (responseCode == 200) {
			          // 获得输入流，从服务器端获得数据
					  inputStream = (InputStream) httpConnection.getInputStream();
			          if(preBankFront!=null&&preBankFront.bankCode.equals("CCB04")){
			          	  retStr[1] = changeInputStream1(inputStream);
					  }else {
						  retStr[1] = changeInputStream(inputStream, p_charsetName);
					  }
			          inputStream.close();
			        //}
			        //else{
			        //	retStr[1] = httpConnection.getResponseMessage();
			        //}
			        /*outputStream.close();
			        outputStream = null;
			        inputStream = null;*/
				}
				catch (IOException e) {
					FGBiz.limitMsg.exception(getLogCode(),e);
					retStr[1] = e.toString();//LogHelper.getStackTrace(e);//e.getMessage();
					String exMsg = LogHelper.getStackTrace(e);
					sbLog.append(exMsg+"\r\n");
					setBankFrontException(exMsg);
				}
			}
			try {
				if(inputStream != null){
					inputStream.close();
				}
			}
			catch (IOException e) {
				FGBiz.limitMsg.exception(getLogCode(),e);
				sbLog.append(LogHelper.getStackTrace(e)+"\r\n");
			}
			try {
				if(outputStream != null){
					outputStream.close();
				}
			}
			catch (IOException e) {
				FGBiz.limitMsg.exception(getLogCode(),e);
				sbLog.append(LogHelper.getStackTrace(e));
			}
			httpConnection.disconnect();
		}
		else{
			retStr[1] = connMsg;
		}
		return retStr;
	}
	
	private String[] initHttpConnection(byte[] p_upBytes){
		String[] retStr = new String[]{"",""};
		retStr[0] = connCode;
		if(connectTimeout > 0){
			httpConnection.setConnectTimeout(connectTimeout);
			connectTimeout = 0;
		}
		if(readTimeout > 0){
			httpConnection.setReadTimeout(readTimeout);
			readTimeout = 0;
		}
		try {
			httpConnection.setDoInput(true);// 从服务器获取数据
			
			httpConnection.setUseCaches(false);
			if(p_upBytes != null){
				httpConnection.setDoOutput(true);// 向服务器写入数据
				httpConnection.setRequestMethod("POST");
				httpConnection.setRequestProperty("Content-Length", String.valueOf(p_upBytes.length));
			}
			else{
				httpConnection.setRequestMethod("GET");
			}
		}
		catch (IOException e) {
			FGBiz.limitMsg.exception(getLogCode(),e);
			retStr[0] = ConnState.FAIL;
			retStr[1] = LogHelper.getStackTraceFirstLine(e);
			if(retStr[1].contains("ConnectException")){
				retStr[1] = "连接" + serverAddr + "异常：" + retStr[1];
			}
//			retStr[1] = e.getMessage();//; LogHelper.getStackTrace(e)
			String exMsg = LogHelper.getStackTrace(e);
			sbLog.append(exMsg+"\r\n");
			setBankFrontException(exMsg);
		}
		return retStr;
	}
	
	/**提交字节，不需要响应，提交后就返回，不读取响应*/
	public String[] uploadNoNeedResp(byte[] p_upBytes){
		String[] retStr = initHttpConnection(p_upBytes);
		OutputStream outputStream = null;
		if(retStr[0].length() == 0){
			try{
				outputStream = (OutputStream) httpConnection.getOutputStream();
				if(p_upBytes != null){
					outputStream.write(p_upBytes);
					outputStream.flush();
					outputStream.close();
					outputStream = null;
				}
				int responseCode = httpConnection.getResponseCode();
				if (responseCode != 200) {
					retStr[1] = httpConnection.getResponseMessage();
				}
			}
			catch(SocketTimeoutException ex){
				retStr[1] = ex.toString();
			}
			catch (IOException e) {
				FGBiz.limitMsg.exception(getLogCode(),e);
				retStr[0] = ConnState.IO_Exception;
				retStr[1] = e.toString();//LogHelper.getStackTrace(e);//e.getMessage();
				String exMsg = LogHelper.getStackTrace(e);
				sbLog.append(exMsg+"\r\n");
				setBankFrontException(exMsg);
			}
		}else{
			retStr[1] = connMsg;
		}
		try {
			if(outputStream != null){
				outputStream.close();
			}
		}
		catch (IOException e) {
			FGBiz.limitMsg.exception(getLogCode(),e);
			sbLog.append(LogHelper.getStackTrace(e));
		}
		httpConnection.disconnect();
		
		return retStr;
	}
	
	/**下载文件*/
	public String[] download(String pSaveToPath){
		String[] retStr = initHttpConnection(null);
		InputStream inputStream = null;
		FileOutputStream fileOutStream = null;
		if(retStr[0].length() == 0){
			try{
				int responseCode = httpConnection.getResponseCode();
				if (responseCode == 200) {
					File localFile = new File(pSaveToPath);
					if(!localFile.getParentFile().exists()){
						localFile.getParentFile().mkdirs();
					}
					fileOutStream = new FileOutputStream(localFile);
					// 获得输入流，从服务器端获得数据
					inputStream = (InputStream) httpConnection.getInputStream();
					byte[] buffer = new byte[10240];
	                int ch = 0;
	                while ((ch = inputStream.read(buffer)) != -1) {
	                	fileOutStream.write(buffer, 0, ch);
	                }
	                
	                inputStream.close();
	                inputStream = null;
	                
	                fileOutStream.flush();
	                fileOutStream.close();
	                fileOutStream = null;
	                
	                
			    }else{
			    	retStr[0] = "http_code:"+responseCode;
			    	retStr[1] = httpConnection.getResponseMessage();
			    }
			}
			catch(SocketTimeoutException ex){
				retStr[0] = ConnState.IO_Exception;
				retStr[1] = ex.toString();
				FGBiz.limitMsg.exception(getLogCode(),ex);
			}
			catch (IOException e) {
				FGBiz.limitMsg.exception(getLogCode(),e);
				retStr[0] = ConnState.IO_Exception;
				retStr[1] = e.toString();//LogHelper.getStackTrace(e);//e.getMessage();
				String exMsg = LogHelper.getStackTrace(e);
				sbLog.append(exMsg+"\r\n");
				setBankFrontException(exMsg);
			}
		}else{
			retStr[1] = connMsg;
		}
		try {
			if(inputStream!=null){
				inputStream.close();
			}
			if(fileOutStream!=null){
				fileOutStream.close();
			}
		}
		catch (IOException e) {
			FGBiz.limitMsg.exception(getLogCode(),e);
			sbLog.append(LogHelper.getStackTrace(e));
		}
		httpConnection.disconnect();
		
		return retStr;
	}

	public static String changeInputStream(InputStream inputStream, String encode) throws IOException{
		// ByteArrayOutputStream 一般叫做内存流
	    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
	    byte[] data = new byte[1024];
	    int len = 0;
	    String result = "";
	    if (inputStream != null) {
	    	while ((len = inputStream.read(data)) != -1) {
	    		byteArrayOutputStream.write(data, 0, len);
	    	}
	    	result = new String(byteArrayOutputStream.toByteArray(), encode);
	    	byteArrayOutputStream.close();
	    }

	    return result;
	}

	//CCB04银行传送过来的数据需要做base64转换，不能直接转换成字符串，防止数据丢失
	public static String changeInputStream1(InputStream inputStream) throws IOException{
		// ByteArrayOutputStream 一般叫做内存流
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		byte[] data = new byte[1024];
		int len = 0;
		String result = "";
		if (inputStream != null) {
			while ((len = inputStream.read(data)) != -1) {
				byteArrayOutputStream.write(data, 0, len);
			}
			result = new BASE64Encoder().encode(byteArrayOutputStream.toByteArray());
			byteArrayOutputStream.close();
		}

		return result;
	}

}
